
import java.util.ArrayList;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Nathan
 */
public class Elevator extends AbstractElevator implements Runnable {
    
    private int currentFloor;
    private int destinationFloor;
    private int numRiders;
    private long doorOpenTime;
    private final int MAXTIME = 50;
    private int numPpLInSIDeThizsJUnk;
    // counter of all requests at each floor
    private int[] counter;
    private Building building;
    private boolean goingUp;
    
    public Elevator(int numFloors, int elevatorId, int maxOccupancyThreshold, Building b) {
        super(numFloors, elevatorId, maxOccupancyThreshold);
        currentFloor = 1;
        destinationFloor = 1;
        numRiders = 0;
        counter = new int[numFloors];
        building = b;
        goingUp = false;
        numPpLInSIDeThizsJUnk = 0;
    }
    
    public int getCurrentFloor() {
        return currentFloor;
    }
    
    public boolean hasSpace() {
    	return numPpLInSIDeThizsJUnk < getMaxOccupancy();
    }
    
    /* Signal incoming and outgoing riders */
    public synchronized void OpenDoors() {
        doorOpenTime = System.currentTimeMillis();
        building.write(Thread.currentThread().getName() + " on F" + currentFloor +
                    " opens");
    }   

    /* When capacity is reached or maxOpenDoorTimeLimit reached or the
     * outgoing riders are exited and incoming riders are in. 
     */
    public void ClosedDoors() {
        //while (System.currentTimeMillis() - doorOpenTime < MAXTIME) {
    	while(true) {
    		synchronized (this) {
    			this.notifyAll();
    		}
            if (numRiders == getMaxOccupancy() || counter[currentFloor-1] == 0) {
                building.write(Thread.currentThread().getName() + " on F" + currentFloor +
                        " closes");
                return;
            }
    	}
        //}
    }

    /* Go to a requested floor */
    public void VisitFloor(int floor) {
    	while(floor != currentFloor) {
            if (counter[currentFloor-1] != 0) {
                OpenDoors();
                ClosedDoors();
            }
    		
    		if(floor-currentFloor > 0)
    			moveUp();
    		else
    			moveDown();
    	}
    	if (counter[currentFloor-1] != 0) {
            OpenDoors();
            ClosedDoors();
        }
    }

    public void run() {
        while(true) {
        	VisitFloor(destinationFloor);
        }
    }

    /* Elevator rider interface (part 1): invoked by rider threads. 
     */

    /* Enter the elevator */
    public synchronized void Enter() {
    	numPpLInSIDeThizsJUnk++;
        counter[currentFloor-1]--;
    }

    /* Exit the elevator */
    public synchronized void Exit() {
    	numPpLInSIDeThizsJUnk--;
        counter[currentFloor-1]--;
    }

    /* Request a destination floor once you enter */
    public synchronized void RequestFloor(int floor) {
        counter[floor-1]++;
        if (destinationFloor < floor && goingUp) {
        	destinationFloor = floor;
        }
        else if (destinationFloor > floor && !goingUp) {
        	destinationFloor = floor;        	
        }
    }    
    
    public synchronized void floorCall(int floor) {
    	counter[floor-1]++;
    	do {
			try {
				this.wait();
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}	
    	} while(getCurrentFloor() != floor);
    	
    	if (!hasSpace())
    		counter[floor-1]--;
    }
    
    public void moveUp() {
    	currentFloor++;
        building.write(Thread.currentThread().getName() + " moves up to F" + currentFloor);
    }
    
    public void moveDown() {
    	currentFloor--;
        building.write(Thread.currentThread().getName() + " moves down to F" + currentFloor);
    }
    
    public synchronized boolean isIdle() {
    	for (int i=0; i<counter.length; i++) {
    		if (counter[i] != 0) return false;
    	}
    	return destinationFloor == currentFloor;
    }
    
    public boolean isGoingUp() {
    	return goingUp;
    }

    public synchronized void setDest(int floor) {
    	destinationFloor = floor;
    }
    
    public synchronized void setGoingUp(boolean up) {
    	goingUp = up;
    }
    
    public int getDest(){
    	return destinationFloor;
    }
    /* Other methods as needed goes here */
}